home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Languages
/
Mops 2.7
/
Mops ƒ
/
Files
< prev
next >
Wrap
Text File
|
1995-11-26
|
14KB
|
599 lines
\ Files - file object and loader
cr .( loading Files...)
cl1 \ In case we're reloading
' cl1 -> abortVec
0 -> quitvec
0 value SFDlgHook \ Used in std file calls. If non-zero,
\ points to the proc to be called while
\ the std file dialog is up.
-39 constant EOF \ EOF error return
-43 constant FNF \ File not found ditto
-300 constant FILE-MARK
\ Marks the start of a loaded file - we plant some useful info there.
\ We put the file name in the dic as if it's a definition name, but use
\ file-mark as a "handler code". Then after that we put the useful info.
\ See extrasMod.
false value ASYNCH?
false value ENDLOAD?
false value LOG?
0 value OPEN_CNT
0 value CLOSE_ERR_CNT
forward CREATE_LOG
forward WRITE_LOG
string $LG1
string $LG2
: ASYNCH true -> asynch? ;
: IOWAIT BEGIN busy 0EXIT pause AGAIN ;
: (ASY) \ ( fcb -- ) Sets up for a low-level asynchronous read or write.
IOwait
-> busy setCP ;
: VOLNAME? { str -- b }
reset: [ str ]
58 str chsearch: [ str ]
NIF false EXIT THEN
lim: [ str ] 2 >= ;
forward OPEN_WITH_PATHS
false value USE_PATHS?
: HFS? $ 3f6 w@x 0> ;
variable MyDocName 28 allot
: MyDoc \ ( -- addr len )
MyDocName count ;
\ Standard file package support
: SFLOC { \ ht wd -- x:y }
\ Computes screen coordinates for top left of
\ SF dialog box. Centers the box horizontally, and a bit above
\ the center vertically.
screenbits -> ht -> wd 2drop
ht 3 / 80 - 0 max -> ht
wd 2/ 170 - 0 max -> wd
wd ht pack ;
:class SFrec super{ object }
record
{ int Good
var fType
int vRefNum
int Version
64 bytes Filename \ max size is 64
}
4 ordered-col fTypes \ list of filetypes
:m GetVRefNum: get: vRefNum ;m
:m GetName: addr: FileName ;m
:m CALL: \ ( routine# -- bool ) Calls a Standard File Package routine.
SFDlgHook ^base rot makeint trap$ A9EA
get: good ;m
:m STDGET: ( type0 ...typeN ) { #types -- bool }
clear: fTypes #types 0>
IF #types 0 DO add: fTypes LOOP THEN
SFloc 0 0 #types makeint ixAddr: fTypes
2 call: self ;m
:m STDPUT: { pAddr pLen nAddr nLen -- bool }
pAddr pLen pad place
SFloc pad nAddr nLen str255
1 call: self ;m
;class
objHandle SFHDL
objPtr SFOBJ class_is SFrec
\ DO_OPEN does the hard work for OPEN: file. First, if either the DirID
\ or the vol ref# is non-zero, we rashly assume we know which folder we
\ want, and just do an open. We also do that if we're not running under HFS.
\ Then, if we get through to here, we need to look at the paths. But wait!
\ First, we check the default folder by just doing a plain open anyway! If
\ this fails with a "file not found", we call ?USE_PATHS which either does
\ nothing (if we're not using a path designator file), or calls our PATHSMOD
\ module to look at a PD file and try using those paths to find the wanted
\ file.
: DO_OPEN { fcb mode -- rc }
1 ++> open_cnt
^base 48 + @ \ DirID
^base 22 + w@ \ vol ref#
or HFS? not or \ Either non-zero, or not HFS?
use_paths? not or \ Or paths disabled?
IF \ Yes: just do a normal open, and get out.
fcb mode (open) EXIT
THEN
\ Maybe use HFS paths:
fcb mode (open) dup 0EXIT \ Try default folder first
\ -- out if we found it
dup FNF <> ?EXIT \ If err wasn't FNF, get out
use_paths? 0EXIT \ If paths disabled, out with FNF
drop fcb mode open_with_paths ;
:class FILE super{ object } general
134 bytes FCB \ max parameter block (108 but for hgetvinfo)
record FSSpec
{ int FSvRefNum
var FSDirID
64 bytes FileName
}
:m CLEAR: \ Clears the fcb, except for the filename.
^base 18 erase ^base 22 + 112 erase ;m
:m SETNAMEPTR: \ Sets filename pointer in the FCB.
^base 140 + ^base !fptr ;m
:m NAME: \ ( addr len -- ) Assigns file name to fcb. Rest cleared.
setNamePtr: self clear: self
^base 140 + >r \ Addr of filename (at end of fcb)
r@ 64 blanks
( addr len ) 64 min r> >str255 drop ;m
:m SETDIRID: \ ( dirid -- ) Sets the DirID for the fcb
^base 48 + ! ;m
:m GETDIRID: \ ( -- dirid ) Gets the DirID for the fcb
^base 48 + @ ;m
:m GETFREF: \ ( -- fref ) Gets the file ref number.
^base 24 + w@ ;m
:m SETFREF:
^base 24 + w! ;m
:m SETVREF: \ ( vref# -- ) Sets the volRefNum for the fcb
^base 22 + w! ;m
:m GETVREF: \ ( -- vref# ) Gets the volRefNum for the fcb
^base 22 + w@ ;m
:m CLOSE: \ ( -- rc ) Needs to clear the file RefNum field,
\ as advised in Mac Tech note # 102. In fact we clear
\ the whole fcb except the name and Vref, so we can reuse
\ the fcb for a subsequent operation without the extra info
\ left by read and write calls being interpreted as HFS info.
^base (close) getVref: self clear: self setVref: self
dup if 1 ++> close_err_cnt else -1 ++> open_cnt then ;m
:m OPEN: \ ( -- rc )
^base 0 do_open ;m
:m OPENREADONLY:
^base 1 do_open ;m
:m NEW: ^base (make) ;m
:m DELETE: ^base (delete) ;m
:m MOVETO: \ ( byteoffset -- rc ) Positions relative to start of file
^base 1 rot (lseek) ;m
:m POS: \ ( -- byteoffset )
^base $ 2E + @ ;m
:m SETEOF: \ ( pos -- rc ) Sets end-of-file to absolute byte position
^base 28 + ! ^base fdos$ a012 ;m
:m CREATE: { \ volID -- rc }
\ Opens and resets file or creates new if not present.
1 ++> open_cnt
^base 0 (open) \ Attempt to open - don't use paths
?dup
IF dup FNF =
IF drop
new: self ?dup NIF ^base 0 (open) THEN
THEN
ELSE
0 setEOF: self
THEN ;m
:m LAST: \ Positions to end of file.
big# moveto: self drop ;m
:m SIZE: \ ( -- #bytes ) Returns logical eof for file currently open
^base fdos$ a011 drop ^base 28 + @ ;m
:m BYTESREAD: \ ( -- n ) Returns actual bytes read.
^base 40 + @ ;m
:m FCB: ( -- fcb ) ^base ;m
:m RESULT: \ ( -- rc ) Returns the last I/O result code.
^base 16 + w@ ;m
:m MODE: \ ( posMode -- ) Sets position mode
^base 44 + w! ;m
:m WAIT: \ ( -- rc ) Waits for asynch I/O on this file to finish.
BEGIN ^base busy =
NIF ^base 16 + w@x EXIT THEN
pause
AGAIN ;m
:m ?WAIT: \ ( rc1 -- rc2 )
asynch?
NIF drop wait: self
ELSE false -> asynch?
THEN ;m
:m READ: \ ( addr length -- rc )
0 mode: self ^base swap rot
^base (asy) (read) ?wait: self ;m
:m READLINE: \ ( addr maxLen -- rc ) Reads terminating with CR
$ 0D80 mode: self ^base swap rot
^base (asy) (read) ?wait: self ;m
:m WRITE: \ ( addr length -- rc )
^base swap rot
^base (asy) (write) ?wait: self ;m
:m SETNAME: \ Gets name from input stream, and assigns to fcb.
& " parse-word name: self ;m
:m GETNAME: \ ( -- addr len ) Returns filename
addr: fileName count ;m
:m PRINT: \ Prints the filename.
getName: self type ;m
:m GETFILEINFO: \ ( -- rc ) Fills the parameter block with file info
^base fdos$ A20C ;m
:m SETFILEINFO: \ ( -- rc )
^base fdos$ A20D ;m
:m SET: { ftyp sig -- } \ Sets file type, signature.
getDirID: self \ Save DirID
0 setDirID: self \ and clear it (otherwise we'll get
getFileInfo: self drop \ "file not found")
sig ^base $ 24 + ! \ Set signature
ftyp ^base $ 20 + ! \ Set type
0 setDirID: self
setFileInfo: self drop
setDirID: self ;m \ Restore DirID
:m DRIVE: \ ( drive# -- ) set default drive to drive#
clear: self setVRef: self ^base fdos$ a015
?error 165 ;m
:m ACCEPT: { addr len \ #chrs eof? -- #chrs eof? } \ ACCEPTs from disk.
echo? IF addr len erase THEN \ So the typed line is OK
addr len readLine: self -> eof?
bytesRead: self eof? NIF 1- THEN -> #chrs
#chrs 0= eof? and IF 0 true EXIT THEN
addr #chrs + c@ 13 <>
IF \ Overlength line. Probably a comment.
BEGIN \ Gobble to CR or EOF
pad 100 readLine: self -> eof?
eof?
IF true
ELSE pad bytesRead: self 1- + c@ 13 =
THEN
UNTIL
THEN
#chrs -> len
echo?
IF addr len type cr THEN
BEGIN \ Loop to convert tabs to blanks
addr len 9 scan -> len -> addr
len
WHILE
bl addr c!
REPEAT
#chrs false ;m
:m RENAME: { taddr tlen -- rc }
taddr tlen str255
^base 28 + ! ^base fdos$ A00B ;m
:m GETTYPE: \ ( -- type )
^base 32 + @ ;m
:m FLUSHVOL:
^base fdos$ A013 drop ;m
:m CLASSINIT: clear: self setNamePtr: self ;m
\ Standard file package calls. If the value SFDlgHook is non-zero, we take it as the
\ address of a dialog hook routine.
private
:m SFPCALL: \ ( various get? -- b ) Calls a Standard File Package routine
classinit: self \ Make sure name pointer is right
['] SFrec newObj: SFhdl
obj: SFhdl -> SFobj
IF stdGet: SFobj ELSE stdPut: SFobj THEN
IF getVRefNum: SFobj clear: self setVref: self
getName: SFobj count addr: fileName place
true
ELSE
false
THEN
release: SFhdl ;m
public
:m STDGET: \ ( type0 ...typeN #types -- bool )
true sfpCall: self ;m
:m STDPUT: \ ( pAddr pLen nAddr nLen -- bool )
false sfpCall: self ;m
;class
' fFcb set_to_class file \ Make fFcb a FILE objPtr
6 fFcb 8 - w!
' file fFcb 6 - reloc!
-6 fFcb 2 - w!
\ GetDirID returns the dirID of the last directory opened by a
\ standard file call.
: GETDIRID $ 398 @ ;
\ FileList keeps a stack of open load files for nested loads.
objPtr TOPFILE class_is file
:class FILELIST super{ handleArray }
:m DROP:
top: super \ Give error if empty
close: topFile drop
drop: super
size: super NIF nilP ELSE obj: self THEN
-> topFile
false -> endload? ;m
:m PUSHNEW: \ Adds a new file to the stack
['] file pushNewObj: self
false -> endload?
obj: self -> topFile \ Note this locks the file object
\ -- this is what we want.
0 setVref: topFile ;m
:m CLEAR: \ Removes all currently open files
false -> endload?
get: size 0EXIT
type# 180 ( File stack: ) cr top: self
get: size FOR
print: topFile cr drop: self
NEXT ;m
;class
10 fileList LOADFILE
0 value FILESTART_DP
0 value CNT
0 value SvLATEST
: LOGIT
state 0EXIT \ Out if we're not compiling
here filestart_DP - pad w!
pos: topFile src-len -
pad 2+ !
pad 6 add: $lg1 ;
0 value LASTPOS
: LOGCR
state 0EXIT
here lastPos <= ?EXIT
here -> lastPos
pad 14 erase
here filestart_DP - pad w!
latest svLatest <> IF true pad 4+ c! latest -> svLatest THEN
pad 14 add: $lg2 ;
: (FREFILL) \ ( -- flag ) Does a refill from a file.
echo?
IF ?pause
ELSE cnt NIF ?pause 20 -> cnt else 1 --> cnt THEN
THEN
log? IF logCR THEN
tib tibLen accept: topfile ( #chrs eof? ) -> endload? #tib !
set_source endload? 0= ;
' (Frefill) -> Frefill
: (LD)
BEGIN
endload? IF false -> endload? EXIT THEN
topfile -> source-ID (Frefill) IF interpret THEN
state not echo? and fWind? and IF ok THEN
AGAIN ;
false value DO_CR?
: ?file_open_error { OSErr -- }
OSErr 0EXIT \ out if no error
getName: topfile type
OSErr FNF = IF 132 die THEN \ file not found
OSErr . cr 155 die \ other error opening file
;
: LOADTOP { \ svCurs svHere svDepth -- }
\ Interprets the file as a Mops source file.
openReadOnly: topfile ?file_open_error
curs -> svCurs -curs
cr
size: loadFile 2* spaces type# 173 ( Loading: )
getName: topfile type
log? IF
create_log ['] logit -> logVec
0 -> svLatest
THEN
here -> svHere depth -> svDepth
false -> endload? false -> do_cr?
(ld)
['] null -> logvec
close: topfile drop log? IF write_log THEN
do_cr?
IF cr size: loadFile 2* ELSE 2 THEN spaces true -> do_cr?
here svHere - ." Size: " .
size: loadFile 1 <= IF cr THEN
depth svDepth <> IF cr msg# 75 THEN
\ Warning - stack depth different after load
svCurs -> curs ;
: ENDLOAD true -> endload? 0 -> src-len ;
\ Nesting loader. Usage: // filename
: // { \ svcurs addr len -- }
pushNew: loadFile setName: topFile
getName: topFile mark_file
loadTop
drop: loadFile ;
\ ======= Module support ========
: NOMOD -1 -> modbase -1 -> MBcomp 0 -> CompMod ;
: LDFROMMOD { newModbase \ svModbase svMBcomp -- }
\ Load from a module. We save and restore the current
\ modbase and MBcomp value, in case the load changes them.
modbase -> svModbase MBcomp -> svMBcomp
newModbase dup -> modbase -> MBcomp
loadtop
svModbase -> modbase svMBcomp -> MBcomp ;
\ ========== Save ==========
'type COM constant SAVETYPE \ file type = 'COM '
'type MOPS constant SAVESIG \ Signature = 'MOPS'
: SAVE_THIS \ ( -- addr len ) Defines what to save
['] latest here over - ;
\ PURGE gets rid of all loaded modules. It is defined in the file Modules.
\ SAVE needs to call it first, so that saved dic images don't appear to
\ reference loaded modules which aren't really loaded. So that we can call
\ SAVE before Modules is loaded, we make PURGE a vector rather than a
\ forward definition.
' null vect PURGE
: (SAVE) { \ savdp savlatest -- rc }
create: ffcb ?error 107
dp -> savdp latest -> savlatest
save_this \ Call before we clobber DP
dp ['] dp - -> dp \ Here we make DP and LATEST relative
latest ['] dp - -> latest \ to DP so we can set them up when
\ saved image is read in
purge \ Purge modules so saved image has them all
\ unloaded
0 -> bufPtr \ Must be zero in saved dics
true -> savingDic? \ Stops PAUSE from doing anything during
\ asynch I/O (could try to call a module,
\ but they're purged)
write: ffcb \ Leave return code on stack for caller
false -> savingDic?
savdp -> dp savlatest -> latest \ and DP and LATEST
savetype savesig set: ffcb
close: ffcb drop
\ type# 101 ( Saved: ) getname: ffcb type cr ;
;
: SAVE \ Takes name from input stream. Redefined later in Frontend.
setname: ffcb (save) ?error 105 ;
\ CL2 is the next cleanup word - it cleans up all file stuff on abort,
\ as well as whatever we were doing before (see CL1 in file Class).
: CL2
clear: loadfile close: ffcb drop
nomod release: $lg1 release: $lg2
['] null -> logvec false -> endload?
false -> savingDic?
cl1 ;
: FILINIT
['] file dup ['] fFcb 4+ reloc!
fFcb 18 + @ \ Name pointer - doc name may not be in fFcb
count 32 min myDocName place
fFcb make_obj
clear: loadfile ;
' filinit -> objinit
' cl2 -> abortvec
: -ECHO false -> echo? ;
: +ECHO true -> echo? ;
cr
.( saving interim.dic. Now type) cr
.( // sys.ld) cr
.( to load the rest of the system.) cr
save interim.dic